/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2005 Copyright (C)
 *
 *  File: flash_info.c
 *
 *  Description: Provide flash information functions.
 *
 *  History:
 *      Date        Author      Version  Comment
 *      ====        ======      =======  =======
 *  1.  2005.5.28   Liu Lan     0.1.000  Initial
 *  2.  2006.4.28   Justin Wu   0.2.000  Re-arch
 *
 ****************************************************************************/

#include <types.h>
#include <sys_config.h>
#include <retcode.h>
#include <bus/flash/flash.h>
#include "flash_data.h"
extern unsigned short sflash_devtp;
extern int sst26_sf_erase_sector(UINT32 sector_addr);
extern int sst26_sf_copy(UINT32 flash_addr, UINT8 *data, UINT32 len);
extern int sst26_sf_read(void *buffer, void *flash_addr, UINT32 len);
extern int sst26_sf_verify(UINT32 flash_addr, UINT8 *data, UINT32 len);

unsigned int flash_sector_size(unsigned int sector)
{
    unsigned char *p;

    if (sector >= flash_info.flash_sectors)
        sector = flash_info.flash_sectors - 1;

    p = (unsigned char *)flash_sector_map + \
          flash_sector_begin[flash_info.flash_id] * 2;
    while (sector >= p[0])
    {
        sector -= p[0];
        p += 2;
    }
    return 1 << p[1];
}

unsigned int flash_sector_align(unsigned long addr)
{
    unsigned int i;
    unsigned int sector_size;

    for (i = 0; i < flash_info.flash_sectors; i++)
    {
        sector_size = flash_sector_size(i);
        if (addr < sector_size)
            break;
        addr -= sector_size;
    }
    return i;
}

unsigned long flash_sector_start(unsigned int sector_no)
{
    unsigned long addr = 0;
    while (sector_no--)
        addr += flash_sector_size(sector_no);
    return addr;
}

unsigned int flash_identify(void)
{
    unsigned long id;
    unsigned long id_buf[3];
    unsigned int s;
    unsigned short i, j;
    unsigned char flash_did;
    unsigned short flash_did_ex;
	unsigned int sflash_0x8c_flag ;

    for (j = 0; j < flash_cmdaddr_num; j++)
    {
        flash_get_id(id_buf, tflash_cmdaddr[j]);
        flash_info.flash_id = FLASHTYPE_UNKNOWN;
		
		sflash_0x8c_flag = 0;
		
        for (i = 0; i < flash_info.flash_deviceid_num * 2; i += 2)
        {
            s = flash_info.flash_deviceid[i + 1];
            id = id_buf[s >> 5];
            s &= 0x1F;
            flash_did = flash_info.flash_deviceid[i];
            if (((id >> s) & 0xFF) == flash_did)
            {
				if (0x17==flash_did) 
				{	  	
					if(((id_buf[0]&0xffffffff)!=0x4d182001));
					else continue;
				}	
				if(0x16==flash_did)
				{
					if(((id_buf[0]&0xffffffff)==0xc2169ec2)) continue;//for MX25L3255D

					if(((id_buf[0]&0xffffffff)==0x8c17418c)) continue;// cari add for ESMT F25L64QA  

				}
				if(0x26==flash_did)
                {
                    if(((id_buf[0]&0xffffffff)==0xc21826c2)) continue;//for MX25L12855E  
                }
				
				if((0x8c==flash_did)&&(0 == sflash_0x8c_flag))
                {
                	
					sflash_0x8c_flag++;
                    if(((id_buf[0]&0xffffffff)==0x8c17418c)) continue;// cari add for ESMT F25L64QA  
                }

				if(0x15==flash_did)
                {
			
                    if(((id_buf[0]&0xffffffff)==0x7f469d7f)) continue;// cari add for Pm25LQ032C  
                }
				
                flash_info.flash_id = flash_info.flash_id_p[i >> 1];
				if(flash_info.set_io)		
					flash_info.flash_io = flash_info.flash_io_p[i >> 1];		
                /* special treatment for SST39VF088 */
                if (flash_info.flash_id == FLASHTYPE_39080 && j == 0)
                    flash_info.flash_id = FLASHTYPE_39088;
				if(0x1a == flash_did&&72==flash_info.flash_deviceid[i + 1])
				{
					if(0!=(id&0xffff0000)&&flash_info.flash_id==FLASHTYPE_S29AL032D_04)
					flash_info.flash_id=FLASHTYPE_S29AL032D_03;
				}
                break;
            }
        }
		
        if (i < flash_info.flash_deviceid_num * 2)
        {
            flash_info.flash_sectors = (unsigned int) \
                (tflash_sectors[flash_info.flash_id]);
            flash_info.flash_size = flash_sector_start(flash_info.flash_sectors);

            if((id_buf[0]&0xffff) == 0x40EF)//W25Q
                flash_info.flash_io = 1;
            else if((id_buf[0]&0xffff) == 0x30EF)//W25X
                flash_info.flash_io = 1; // W25X16AVS1G can't write on M3606 SQI mode   
            else if((id_buf[0]&0xffff) == 0x24c2)//MX25L1635D/MX25L3235D
                flash_info.flash_io = 4;
            else if((id_buf[0]&0xffff) == 0x20c2 && flash_info.flash_size >= 0x200000) //MX25L1605D/MX25L3205D/MX25L6405D
                flash_info.flash_io = 1;
            else if((((id_buf[0]>>8)&0xffff) == 0x3037) || (((id_buf[0]>>8)&0xffff) == 0x2037) && (flash_info.flash_size >= 0x200000))//A25L016,A25L032
                flash_info.flash_io = 2;
			if(( 2== flash_info.flash_io  || 4 == flash_info.flash_io ) && (ALI_S3811==sys_ic_get_chip_id())&&(*((volatile unsigned long*)0xb8000480)&(1<<13)) == 0) //for S3811
				flash_info.flash_io  = 1;
			if(((id_buf[0]&0xffff) == 0x9ec2) &&(ALI_S3602F==sys_ic_get_chip_id()))
			{
			
				*((volatile UINT32 *)(0xb802e000+0x98)) |= 1<<28;////for MX25L3255D
			}
    
			if(sys_ic_get_chip_id()==ALI_S3811 || sys_ic_get_chip_id()==ALI_S3281) //for C3811 3281
			{
				flash_info.flash_io = 1;
			}
    
            if(flash_info.set_io)
                flash_info.set_io(flash_info.flash_io, 0);			
            break;
        }
        for (i = 0; i < flash_info.flash_deviceid_num_ex * 2; i += 2)
        {
            s = flash_info.flash_deviceid_ex[i + 1];
            id = id_buf[(s & 0xff) >> 5];
            flash_did_ex = flash_info.flash_deviceid_ex[i];
			if ((unsigned char)((id >> (s & 0x1F)) & 0xFF) == (unsigned char)(flash_did_ex & 0xFF) && \
                (unsigned char)((id >> ((s >> 8) & 0x1F)) & 0xFF) == (unsigned char)((flash_did_ex >> 8) & 0xFF))
            {
                flash_info.flash_id = flash_info.flash_id_p_ex[i >> 1];
                break;
            }
        }
        if (i < flash_info.flash_deviceid_num_ex * 2)
        {
            flash_info.flash_sectors = (unsigned int) \
                  (tflash_sectors[flash_info.flash_id]);
            flash_info.flash_size = flash_sector_start(flash_info.flash_sectors);
	     		
            break;
        }        
      
        
    }
    if(sflash_devtp == 0x26BF)
    {
        sst26_sf_get_id(id_buf, tflash_cmdaddr[0]);
        flash_info.get_id = sst26_sf_get_id;
        flash_info.erase_sector = sst26_sf_erase_sector;
        flash_info.verify = sst26_sf_verify;
        flash_info.write = sst26_sf_copy;
        flash_info.read = sst26_sf_read;	
    }
    return j < flash_cmdaddr_num;
}
